/*
Copyright (C) 2008-2010 Vana Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.

This program is distributed in the hope that it will be useful,
ut WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "../provider/DataProvider.h"
#include "Inventory.h"
#include "Equip.h"
#include "Item.h"
#include "Map.h"
#include "Maps.h"
#include "../tools/PacketCreator.h"
#include "PlayerInventory.h"
#include "PlayerShop.h"
#include "Player.h"
#include "../net/world/World.h"
#include "../net/world/Worlds.h"

PlayerShop::PlayerShop(Player *player, int itemid, const string &description) :
ownerid(player->getID()),
ownername(player->getName()),
mapid(player->getMap()->getID()),
itemid(itemid),
description(description),
itemsbought(0),
//pos(player->getPosition().x, player->getPosition().y),
open(false) {
	id = Maps::getPlayerShopId();
}

void PlayerShop::addItem(PlayerShopItem *item) {
	items[getNumItems()] = item;
}

void PlayerShop::removeItem(short slot) {
	for (unsigned char i = 0; i < getNumItems(); i++) {
		if (i > slot) {
			items[i - 1] = getItem(i);
			if (i == (getNumItems() - 1)) {
				items.erase(i);
			}
		}
		else if (getItem(i + 1) == 0) {
			items.erase(i);
		}
	}
}

PlayerShopItem * PlayerShop::getItem(short slot) {
	return ((items.find(slot) != items.end()) ? items[slot] : 0);
}

void PlayerShop::returnItem(short slot) {
	Player *owner = getOwner();
	PlayerShopItem *sellItem = getItem(slot);
	if (sellItem != 0 && sellItem->getBundles() > 0) {
		Item *item = sellItem->getItem();
		if (!IS_STAR(item->getID()))
			item->setAmount(sellItem->getBundles() * sellItem->getQuantity());
		char inv = INVENTORY(item->getID());
		slot = sellItem->getSlot();
		Item *olditem = owner->getInventories()->getItemBySlot(inv, slot);
		if (olditem != 0) {
			if (IS_STAR(item->getID()) && olditem->getID() == item->getID() && olditem->getAmount() < DataProvider::getInstance()->getItemMaxPerSlot(item->getID())) {
				if (item->getAmount() + olditem->getAmount() > DataProvider::getInstance()->getItemMaxPerSlot(item->getID())) {
					short amount = DataProvider::getInstance()->getItemMaxPerSlot(item->getID()) - olditem->getAmount();
					item->setAmount(item->getAmount() - amount);
					olditem->setAmount(DataProvider::getInstance()->getItemMaxPerSlot(item->getID()));
					//InventoryPacket::addItem(owner, inv, slot, olditem, true);
				}
				else {
					item->setAmount(item->getAmount() + olditem->getAmount());
					owner->getInventories()->removeItemBySlot(inv, slot, 1);
					owner->getInventories()->giveItem(item);
					//InventoryPacket::addItem(owner, inv, slot, item, true);
				}
			}
		}
		else {
			owner->getInventories()->giveItem(item);
			//InventoryPacket::addNewItem(owner, inv, slot, item, true);
		}
	}
}

void PlayerShop::returnItems(bool sendtoplayer) {
	Player *owner = getOwner();
	for (unsigned char i = 0; i < getNumItems(); i++) {
		PlayerShopItem *shopItem = getItem(i);
		if (shopItem != 0 && shopItem->getBundles() > 0) {
			Item *item = shopItem->getItem();
			if (!IS_STAR(item->getID()))
				item->setAmount(shopItem->getBundles() * shopItem->getQuantity());
			char inv = INVENTORY(item->getID());
			short slot = shopItem->getSlot();
			Item *olditem = owner->getInventories()->getItemBySlot(inv, slot);
			int i = DataProvider::getInstance()->getItemMaxPerSlot(item->getID());
			if (olditem != 0) {
				if (IS_STAR(item->getID()) && olditem->getID() == item->getID() && olditem->getAmount() < DataProvider::getInstance()->getItemMaxPerSlot(item->getID())) {
					if (item->getAmount() + olditem->getAmount() > DataProvider::getInstance()->getItemMaxPerSlot(item->getID())) {
						short amount = DataProvider::getInstance()->getItemMaxPerSlot(item->getID()) - olditem->getAmount();
						item->setAmount(item->getAmount() - amount);
						olditem->setAmount(DataProvider::getInstance()->getItemMaxPerSlot(item->getID()));
						if (sendtoplayer) {
							//InventoryPacket::addItem(owner, inv, slot, olditem, false);
						}
					}
					else {
						item->setAmount(item->getAmount() + olditem->getAmount());
						owner->getInventories()->removeItemBySlot(inv, slot, 1);
						owner->getInventories()->giveItem(item);
						if (sendtoplayer) {
							//InventoryPacket::addItem(owner, inv, slot, item, false);
						}
					}
				}
			}
			else {
				if (IS_EQUIP(item->getID())) {
					item = new Equip(*(Equip*)item);
					owner->getInventories()->giveItem(item);
				} else {
					owner->getInventories()->giveItem(item);
				}
				if (sendtoplayer) {
					//InventoryPacket::addNewItem(owner, inv, slot, item, false);
				}
			}
		}
	}
}

void PlayerShop::buyItem(Player *player, short slot, short quantity) {
	PlayerShopItem *shopItem = getItem(slot);
	if (shopItem->getBundles() > 0) {
		int price = shopItem->getPrice() * quantity;
		if (price >= 0 && player->getMesos() >= price) {
			price = shopItem->getPrice();
			player->setMesos(player->getMesos() - (price * quantity));
			getOwner()->setMesos(getOwner()->getMesos() + (price * quantity));
			if (!IS_STAR(shopItem->getItem()->getID())) {
				Item *item = new Item(shopItem->getItem()->getID());
				item->setAmount((item->getAmount() * quantity));
				player->getInventories()->giveItem(item);
			}
			else {
				player->getInventories()->giveItem(shopItem->getItem());
			}
			shopItem->setBundles(shopItem->getBundles() - quantity);

			getOwner()->send(PacketCreator().playerShopUpdateItems(this));
			for (unsigned char i = 0; i < 3; i++) {
				if (getVisitor(i) != 0) {
					getVisitor(i)->send(PacketCreator().playerShopUpdateItems(this));
				}
			}
			if (shopItem->getBundles() == 0) {
				itemsbought++;
				if (itemsbought == getNumItems()) {
					removeAllVisitors(10);
					getOwner()->send(PacketCreator().playerShopEndMessage(10, true));
					getOwner()->setPlayerShop(0);
					closeShop();
				}
			}
		}
		else {
			player->send(PacketCreator().playerShopError(2));
		}
	}
	else {
		player->send(PacketCreator().playerShopError(7));
	}
}

void PlayerShop::roomChat(Player *player, char slot, const string &chat) {
	getOwner()->send(PacketCreator().roomChat(slot, chat));
	for (unsigned char i = 0; i < 3; i++) {
		if (getVisitor(i) != 0) {
			getVisitor(i)->send(PacketCreator().roomChat(slot, chat));
		}
	}
}

void PlayerShop::closeShop(bool sendtoplayer) {
	getOwner()->getMap()->send(PacketCreator().removePlayerShop(getOwner(), (sendtoplayer ? 0 : getOwner())));
	getOwner()->getMap()->removePlayerShop(getId());
	returnItems(sendtoplayer);
	delete this;
}

char PlayerShop::getEmptyVisitorSlot() {
	for (unsigned char i = 0; i < 3; i++) {
		if (getVisitor(i) == 0) {
			return (i + 1);
		}
	}
	return -1;
}

char PlayerShop::getPlayerSlot(int id) {
	for (unsigned char i = 0; i < 3; i++) {
		Player *visitor = getVisitor(i);
		if (visitor != 0) {
			if (visitor->getID() == id) {
				return (i + 1);
			}
		}
	}
	return 0;
}

Player * PlayerShop::getOwner() {
	return Worlds::getInstance()->getWorld(0)->getPlayerByID(getOwnerId());
}

Player * PlayerShop::getVisitor(char slot) {
	return (visitors.find(slot) != visitors.end() ? visitors[slot] : 0);
}

void PlayerShop::removeAllVisitors(char message) {
	for (unsigned char i = 0; i < 3; i++) {
		Player *visitor = getVisitor(i);
		if (visitor != 0) {
			visitor->send(PacketCreator().playerShopEndMessage(message));
			visitor->setPlayerShop(0);
			visitor->send(PacketCreator().enableAction());
		}
	}
}

void PlayerShop::addVisitor(Player *player) {
	char slot = getEmptyVisitorSlot();
	getOwner()->send(PacketCreator().playerShopAddVisitor(player, slot));
	for (unsigned char i = 0; i < 3; i++) {
		Player *visitor = getVisitor(i);
		if (visitor != 0) {
			visitor->send(PacketCreator().playerShopAddVisitor(player, slot));
		}
	}
	visitors[slot - 1] = player;
	if (getEmptyVisitorSlot() == -1) {
		player->getMap()->send(PacketCreator().showPlayerShop(this));
	}
}

void PlayerShop::removeVisitor(Player *player, bool sendtoplayer) {
	char slot = getPlayerSlot(player->getID());
	visitors.erase(slot - 1);
	getOwner()->send(PacketCreator().playerShopRemoveVisitor(slot));
	for (unsigned char i = 0; i < 3; i++) {
		Player *visitor = getVisitor(i);
		if (visitor != 0) {
			visitor->send(PacketCreator().playerShopRemoveVisitor(slot));
		}
	}
	if (getEmptyVisitorSlot() > -1) {
		player->getMap()->send(PacketCreator().showPlayerShop(this));
	}
}

void PlayerShop::banPlayer(const string &name, char slot) {
	if (getVisitor(slot)->getName() == name) {
		banned[name] = getVisitor(slot)->getID();
		getVisitor(slot)->send(PacketCreator().playerShopEndMessage(5));
		getVisitor(slot)->setPlayerShop(0);
		removeVisitor(getVisitor(slot));
	}
}

bool PlayerShop::isBanned(string name) {
	return (banned.find(name) != banned.end() ? 1 : 0);
}
